home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / demo / demosrc / d_uscensus.pro < prev    next >
Text File  |  1997-07-08  |  44KB  |  1,387 lines

  1. Function USCensus$ZColors, PopulationChanges, PopulationScale
  2. ;
  3. ; Given a population change, determine the color that should be
  4. ; used for that State.
  5. ;
  6. NPopulations = N_Elements(PopulationChanges)
  7. Colors = BytArr(3, NPopulations)
  8. Loss = Where(PopulationChanges lt PopulationScale.RangeMax[0], NLoss)
  9. If (NLoss gt 0) then Begin
  10.     For J = 0, 2 Do Begin
  11.         Colors[J, Loss] = PopulationScale.Colors[J, 0]
  12.     EndFor
  13. EndIf
  14. For I = 1, N_elements(PopulationScale.RangeMax) - 1 Do Begin
  15.     ThisColor = Where(PopulationChanges ge $
  16.         PopulationScale.RangeMax[I - 1] and $
  17.         PopulationChanges lt PopulationScale.RangeMax[I], NThisColor)
  18.     If (NThisColor ne 0) then Begin
  19.         For J = 0, 2 Do Begin
  20.             Colors[J, ThisColor] = PopulationScale.Colors[J, I]
  21.         EndFor
  22.     EndIf
  23. EndFor
  24. BigGain = Where(PopulationChanges ge PopulationScale.RangeMax[ $
  25.     N_elements(PopulationScale.RangeMax) - 1], NBigGain)
  26. If (NBigGain ne 0) then Begin
  27.     For J = 0, 2 Do Begin
  28.         Colors[J, BigGain] = PopulationScale.Colors[J, $
  29.             N_elements(PopulationScale.RangeMax) - 1]
  30.     EndFor
  31. EndIf
  32. Return, Colors
  33. End
  34.  
  35.  
  36. Pro USCensus$New_Coordinates, States, XSize, YSize
  37. ;
  38. ; Calculate State outlines and extruded skirts in normalized
  39. ; coordinates based on the current window size.  This routine
  40. ; is called on initialization.
  41. ;
  42. ;
  43. ; Save the relevant system variables.
  44. ;
  45. PSave = !p
  46. XSave = !x
  47. YSave = !y
  48. ZSave = !z
  49. ;
  50. ; Set up mapping so we can perform coordinate transforms
  51. ; from lat/long to normal coordinates.
  52. ;
  53. Window, /Free, /Pixmap, XSize = XSize, YSize = YSize
  54. Map_Set, 30., -90., Limit = [10.,-68.5, 60.,-120.5], /Lambert
  55. WDelete, !d.window
  56. ;
  57. ; Loop over States, converting lat/lon coordinates to normal
  58. ; coordinates, and extruding the outline along the Z axis to
  59. ; build the "sides" of the States.  The Z height is random
  60. ; in this example, though we do have population data in the
  61. ; State structure.
  62. ;
  63. NPopulation = N_elements(States[0].Population) - 1
  64. For I = 0L, N_elements(States) - 1 Do Begin
  65.     NewOutline = (Convert_Coord(*States[I].pOutline, /Data, $
  66.         /To_Normal))
  67.     NSize = N_elements(NewOutline)/3
  68.     States[I].ZValue = 1.
  69.     If (Ptr_Valid(States[I].pNormalOutline)) then Begin
  70.         *States[I].pNormalOutline = NewOutline[*, 0:NSize - 1]
  71.     EndIf Else Begin
  72.         States[I].pNormalOutline = $
  73.             Ptr_New(NewOutline[*, 0:NSize - 1])
  74.     EndElse
  75. ;
  76. ; Meshing needs to have the first and last outline elements the same
  77. ; otherwise the surface doesn't close.
  78. ;
  79.     NewOutline2 = FltArr(3, NSize + 1)
  80.     NewOutline2[*, 0:NSize - 1] = NewOutline
  81.     NewOutline2[*, NSize] = NewOutline[*, 0]
  82.     Mesh_Obj, 5, VertexList, PolygonList, NewOutline2, P1 = 1, $
  83.         P2 = [0, 0, States[I].ZValue]
  84.     If (Ptr_Valid(States[I].pPolygonList)) then Begin
  85.         *States[I].pPolygonList = Temporary(PolygonList)
  86.     EndIf Else Begin
  87.         States[I].pPolygonList = Ptr_New(PolygonList, /No_Copy)
  88.     EndElse
  89.     If (Ptr_Valid(States[I].pVertexList)) then Begin
  90.         *States[I].pVertexList = Temporary(VertexList)
  91.     EndIf Else Begin
  92.         States[I].pVertexList = Ptr_New(VertexList, /No_Copy)
  93.     EndElse
  94. EndFor
  95. ;
  96. ; Restore plotting environment that changed with MAP_SET.
  97. ;
  98. !x = XSave
  99. !y = YSave
  100. !z = ZSave
  101. !p = PSave
  102. Return
  103. End
  104.  
  105.  
  106. Pro USCensus$Build_Backdrop, BackdropImage, BackdropObject
  107. ;
  108. ; This routine builds the "curtain" or backdrop
  109. ; in front of which the map data are rendered.
  110. ; There's no real magic here.  I just played around
  111. ; with the values until I got the effect I wanted.
  112. ;
  113. ; Note that when texture mapping, IDL operates most
  114. ; efficiently on images that are a) square and b)
  115. ; dimensioned by powers of 2.
  116. ;
  117. ; ZZ defines the surface "height" of the backdrop.
  118. ; XX and YY are the coordinates of each of the
  119. ; ZZ values.
  120. ;
  121. ; Since the image is not a true child of the
  122. ; backdrop object (it's a property), we need
  123. ; to pass that back so we can destroy it later.
  124. ;
  125. ZZ = Findgen(256)^7/1.E15 + .01
  126. Z = FltArr(256, 256)
  127. For I = 0, 255 Do Begin
  128.     Z[I, *] = ZZ
  129. EndFor
  130. XX = FltArr(256, 256)
  131. YY = XX
  132. ;
  133. ; Center the X and Y values
  134. ;
  135. X = Reverse(.25 - Findgen(256)/512)
  136. Y = Findgen(256)/128 - 1
  137. ;
  138. ; The Y values of the mapped image are
  139. ; the same across a row.  The X values
  140. ; spread out toward the bottom of the
  141. ; backdrop so the image appears "splayed".
  142. ;
  143. For I = 0, 255 Do Begin
  144.     YY[I, *] = Y/10.
  145.     XX[*, I] = X * (1 + ((255 - I)/128.)^1.5)
  146. EndFor
  147. ;
  148. ; Create the image that will be mapped onto
  149. ; the coordinates defined above, It's simply
  150. ; an image of vertical stripes with some border
  151. ; pixels.
  152. ;
  153. Image = BytArr(3, 256, 256)
  154. Image[*,254:*, *] = 255
  155. Image[*, *, 254:*] = 255
  156. Image[*,0:3, *] = 255
  157. Image[*, *, 0:2] = 255
  158. ;
  159. ; Now we get obnoxiously partiotic and make
  160. ; the stripes red, white, and blue with some
  161. ; black left in for "shadows".
  162. ;
  163. K = -1
  164. For X = 30, 220, 10 Do Begin
  165.     K = (K + 1) mod 3
  166.     If (K eq 1) then Begin
  167.         Image[*, X:X + 5, *] = 255
  168.     EndIf Else Begin
  169.         For I = 0, 2 Do Begin
  170.             Image[I, X:X + 5, *] = 255 * (I eq K)
  171.         EndFor
  172.     EndElse
  173. EndFor
  174. ;
  175. ; The next trick we perform is to de-focus the
  176. ; image in steps so that pixels nearest the
  177. ; top that appear farthest away are also the most
  178. ; out-of-focus.
  179. ;
  180. For Y = (Size(Image))[2] - 31, 0, -32 Do Begin
  181.     For I = 0, 2 Do Begin
  182. ;
  183. ; Smooth pixels from this row up.  Rows at the
  184. ; top are smoothed more often than rows at the
  185. ; bottom.
  186. ;
  187.         Layer = Smooth(Reform(Image[I, *, Y:*]), 3)
  188.         Image[I, *, Y:*] = Layer
  189.     EndFor
  190. EndFor
  191. ;
  192. ; Create the backdrop image.  Don't forget it's TrueColor!
  193. ;
  194. BackdropImage = Obj_New('IDLgrImage', Image, Interleave = 0)
  195. ;
  196. ; Create the backdrop object using the image object as the
  197. ; texture object.  Keep in mind that the texture mapped image
  198. ; colors are convolved with the COLOR property of the surface
  199. ; object.
  200. ;
  201. BackdropObject = Obj_New('IDLgrSurface', .2 - Z/100., XX, YY, $
  202.     Shading = 1, Style = 2, Texture_Map = BackdropImage, $
  203.     Color = [255, 255, 255], /Texture_Interp)
  204. End
  205.  
  206.  
  207. Pro USCensus$Build_Scale_Legend, PopulationScale, TimesFont, $
  208.     ScaleModel
  209. ;
  210. ; This routine builds the legend for the display.  Each key
  211. ; consists of a color block and a text label associated
  212. ; with each color.  Colors in this example represent relative
  213. ; population change from one decade to the next.
  214. ;
  215. ScaleModel = Obj_New('IDLgrModel')
  216. NScaleColors = N_elements(PopulationScale.RangeMax) + 2
  217. ScaleColorModels = ObjArr(NScaleColors)
  218. ScaleColorImages = ObjArr(NScaleColors)
  219. ScaleColorLabels = ObjArr(NScaleColors)
  220. ColorBlock = BytArr(3, 30, 20)
  221. ;
  222. ; The color white is used when a State is "new"; no census
  223. ; was performed the previous decade.
  224. ;
  225. ScaleColorImages[0] = Obj_New('IDLgrImage', ColorBlock + 255, $
  226.     Interleave = 0, Dimensions = [.1, .2])
  227. ScaleColorLabels[0] = Obj_New('IDLgrText', 'New State', /OnGlass, $
  228.     Location = [.11, -0.06], Color = [255, 255, 255], $
  229.     Font = TimesFont)
  230. ;
  231. ; Red indicates there was population loss compared with the
  232. ; previous decade.
  233. ;
  234. Red = ColorBlock
  235. Red[0, *, *] = 255
  236. ScaleColorImages[1] = Obj_New('IDLgrImage', Red, Interleave = 0, $
  237.     Dimensions = [.1, .2])
  238. ScaleColorLabels[1] = Obj_New('IDLgrText', 'Pop. Loss', /OnGlass, $
  239.     Location = [.11, -0.06], Color = [255, 255, 255], $
  240.     Font = TimesFont)
  241. ;
  242. ; The remaining keys indicate population change between one
  243. ; percentage and the next.
  244. ;
  245. For I = 2, NScaleColors - 1 Do Begin
  246.     ThisColor = ColorBlock
  247.     For J = 0, 2 Do Begin
  248.         ThisColor[J, *, *] = PopulationScale.Colors[J, I - 1]
  249.     EndFor
  250.     ScaleColorImages[I] = Obj_New('IDLgrImage', ThisColor, $
  251.         Interleave = 0, Dimensions = [0.1, 0.2])
  252.     ScaleColorLabels[I]  = Obj_New('IDLgrText', '> ' + $
  253.         StrTrim(Fix(100*(PopulationScale.RangeMax[I - 2] - $
  254.         .99999)), 2) + '%', $
  255.         Color = [255, 255, 255], Location = [0.11, -0.06], $
  256.         /OnGlass, Font = TimesFont)
  257. EndFor
  258. ;
  259. ; Combine the color blocks and text into a models, then
  260. ; translate them so we end up in 2 rows, each with 5 entries.
  261. ;
  262. For I = 0, NScaleColors - 1 Do Begin
  263.     ScaleColorModels[I] = Obj_New('IDLgrModel')
  264.     ScaleColorModels[I]->Add, ScaleColorImages[I]
  265.     ScaleColorModels[I]->Add, ScaleColorLabels[I]
  266.     ScaleColorModels[I]->Translate, -.94 + .4*(I mod 5), $
  267.         -.575*(Fix(I/5)), 0.
  268. EndFor
  269. ScaleLabel = Obj_New('IDLgrText', 'Relative Population Change', $
  270.     Location = [-.98, .6], Font = TimesFont, /OnGlass, $
  271.     Color = [255, 255, 255])
  272. ScaleModel->Add, ScaleLabel
  273. ScaleModel->Add, ScaleColorModels
  274. End
  275.  
  276.  
  277. Pro USCensus$Build_State_Objects, States, StateSurfaceModel, $
  278.     StateObjects, StateSkirts, StateFaces, StateOutlines
  279. ;
  280. ; Create a tessellator object.  Since the State outlines
  281. ; are not all convex, we need to tessellate them before
  282. ; turning them into polygon objects.
  283. ;
  284. Tessellator = Obj_New('IDLgrTessellator')
  285. ;
  286. ; Build each of the State objects.  State objects consist
  287. ; of a) a contiguous outline of the State, b) a filled
  288. ; polygon which serves as the face, and c) an extruded
  289. ; surface which is the "skirt" of the State.
  290. ;
  291. NStates = N_elements(States)
  292. StateSurfaceModel = Obj_New('IDLgrModel')
  293. StateObjects = ObjArr(NStates)
  294. StateSkirts = ObjArr(NStates)
  295. StateFaces = ObjArr(NStates)
  296. StateOutlines = ObjArr(NStates)
  297. For I = 0, NStates - 1 Do Begin
  298.     NewOutline = *States[I].pNormalOutline
  299. ;
  300. ; Make sure lakes are blue.  And that no one lives permanently
  301. ; in them.  Note to Canadians: boundaries are cosmetic only.
  302. ; Neither the United States of America nor Research Systems, Inc.
  303. ; make any formal claims to territories displayed in the map
  304. ; data that do not actually represent previously agreed upon
  305. ; legal boundaries claimed by either entity.
  306. ;
  307.     NewOutline[2, *] = States[I].ZValue
  308.     If (StrPos(States[I].State, 'LAKE') ne -1) then Begin
  309.         Color = [0, 0, 255]
  310.     EndIf Else Begin
  311.         Color = [255, i*3, i*5]
  312.     EndElse
  313. ;
  314. ; Create the State model object.
  315. ;
  316.     StateObjects[I] = Obj_New('IDLgrModel')
  317. ;
  318. ; A black outline serves as the State border.  We define
  319. ; this first in the model so it will overlay the polygon
  320. ; face defined later.  (They lie in the same plane.)
  321. ;
  322.     StateOutlines[I] = Obj_New('IDLgrPolyline', NewOutline, $
  323.         Color=[0, 0, 0], Thick = 1.2, Shading = 0)
  324.     StateObjects[I]->Add, StateOutlines[I]
  325. ;
  326. ; Create the skirt for the State.  Note that we specify
  327. ; backface culling.  Since we won't be looking at the
  328. ; "inside" or back of the scene, we can speed rendering
  329. ; by telling IDL to reject back faces.
  330. ;
  331.     StateSkirts[I] = Obj_New('IDLgrPolygon',*States[I].pVertexList, $
  332.         Polygon = *States[I].pPolygonList, Color = Color, $
  333.         Shading = 1, Reject = 1)
  334.     StateObjects[I]->Add, StateSkirts[I]
  335. ;
  336. ; Create the top face of the State.  We don't define
  337. ; the polygon outlines until a little later after
  338. ; we tessellate the polygon.
  339. ;
  340.     StateFaces[I] = Obj_New('IDLgrPolygon', $
  341.         Color = Color, Shading = 0, Reject = 1)
  342.     StateObjects[I]->Add, StateFaces[I]
  343. ;
  344. ; Set the UValue of the State object to the State's name.
  345. ;
  346.     StateObjects[I]->SetProperty, UValue = States[I].State
  347. ;
  348. ; The following tessellation code compensates for the "concave
  349. ; polygon problem".  Tessellate the outline.
  350. ;
  351.     Tessellator->AddPolygon, NewOutline*500.
  352. ;
  353. ; Precalculate the normals; all the faces point straight up.
  354. ;
  355.     If (Tessellator->Tessellate(Vertices, Polygons)) then Begin
  356. ;
  357. ; Define the State face outline from the tesselation results.
  358. ; We precalculate the normals since we know the faces are all
  359. ; perpendicular to the +Z axis.  This saves some calculation
  360. ; time for IDL.
  361. ;
  362.         Normals = Vertices
  363.         Normals[0:1, *] = 0.
  364.         Normals[2, *] = 1.
  365.         StateFaces[I]->SetProperty, Data = Vertices/500., $
  366.             Polygons = Polygons, Normals = Normals
  367.     EndIf
  368. ;
  369. ; Translate Alaska and Hawaii so they lie closer to the
  370. ; continental USA.
  371. ;
  372.     If (States[I].State eq 'ALASKA') then Begin
  373.         StateObjects[I]->Translate, 0., -.15, 0.
  374.         StateObjects[I]->Translate, -.05, 0., 0.
  375.     EndIf
  376.     If (States[I].State eq 'HAWAII') then Begin
  377.         StateObjects[I]->Translate, .125, 0., 0.
  378.         StateObjects[I]->Translate, 0., -.05, 0.
  379.     EndIf
  380. ;
  381. ; Add the State to the model.  Also reset the
  382. ; tessellator so we're only working on one polygon
  383. ; at a time.
  384. ;
  385.     StateSurfaceModel->Add, StateObjects[I]
  386.     Tessellator->Reset
  387. EndFor
  388. ;
  389. ; We don't need the tessellator anymore.
  390. ;
  391. Obj_Destroy, Tessellator
  392. End
  393.  
  394.  
  395. Pro USCensus$Display_Census_Year, AppState
  396. ;
  397. ; Translate the surface back to the XY plane so we can
  398. ; rotate it about the Y axis.
  399. ;
  400. AppState.StateSurfaceModel->Translate, 0., 0., -.5
  401. ;
  402. ; Rotate the plane about Y back to 0 degrees, then rotate
  403. ; it the specified number of degrees relative to 0.
  404. ;
  405. AppState.StateSurfaceModel->GetProperty, Transform = Transform
  406. ThetaY = ATan(Transform[2, 0], Transform[0, 0])/!dtor
  407. AppState.StateSurfaceModel->Rotate, [0., 1., 0.], -ThetaY
  408. AppState.StateSurfaceModel->Rotate, [0., 1., 0.], AppState.ThetaY
  409. ;
  410. ; Translate the surface back toward the viewer along Z.
  411. ;
  412. AppState.StateSurfaceModel->Translate, 0., 0., .5
  413. ZeroPops = Where(AppState.States.Population[ $
  414.     AppState.CurrentYearIndex] eq 0, NZeroPops)
  415. OkayPops = Where(AppState.States.Population[ $
  416.     AppState.CurrentYearIndex] ne 0, NOKayPops)
  417. ;
  418. ; For States that had no census taken for a given decade,
  419. ; we just draw dark gray boxes at Z = very nearly zero.
  420. ; Lakes are always blue.
  421. ;
  422. For I = 0, NZeroPops - 1 Do Begin
  423.     If (StrPos(AppState.States[ZeroPops[I]].State, 'LAKE') $
  424.         eq -1) then Begin
  425.         AppState.StateFaces[ZeroPops[I]]->SetProperty, $
  426.             Color = [20, 20, 20]
  427.     EndIf
  428.     If (AppState.PreviousScales[ZeroPops[I]] ne 1.e-4) then Begin
  429.         AppState.PreviousScales[ZeroPops[I]] = 1.e-4
  430.         AppState.StateObjects[ZeroPops[I]]->Scale, 1., 1., 1.e-4
  431.     EndIf
  432. EndFor
  433. ;
  434. ; Determine the color to draw the State based on the population
  435. ; change from the previous decade.
  436. ;
  437. If (AppState.CurrentYearIndex lt $
  438.     N_elements(AppState.States[0].Population) - 1) then Begin
  439.     Colors = USCensus$ZColors(AppState.States.Population[ $
  440.         AppState.CurrentYearIndex]/ $
  441.         Float(AppState.States.Population[ $
  442.         AppState.CurrentYearIndex + 1]), $
  443.         AppState.PopulationScale)
  444. EndIf
  445. ;
  446. ; Label the census year.
  447. ;
  448. AppState.TextObject->SetProperty, String = $
  449.     StrTrim(1980 - (AppState.CurrentYearIndex - 1)*10, 2)
  450. ;
  451. ; Loop over the States for which there are valid (non-zero) census
  452. ; data for this decade.
  453. ;
  454. For I = 0, NOkayPops - 1 Do Begin
  455.     ThisState = OkayPops[I]
  456. ;
  457. ; Set the Z scale of the object so that the previous decade = 1 at
  458. ; the current height. This allows us to calculate a relative scale
  459. ; based on the population change.
  460. ;
  461.     AppState.StateObjects[ThisState]->GetProperty, $
  462.         Transform = Transform
  463.     AppState.StateObjects[ThisState]->Scale, 1., 1., $
  464.         1./Transform[2, 2]
  465. ;
  466. ; Scale the height of the State relative to the maximum population.
  467. ;
  468.     ZScale = AppState.States[ThisState].Population[ $
  469.         AppState.CurrentYearIndex]/ $
  470.         AppState.MaxZValue
  471.     AppState.StateObjects[ThisState]->Scale, 1., 1., ZScale
  472. ;
  473. ; Determine the color to make the State, based on relative population
  474. ; change from the previous decade.
  475. ;
  476.     If (StrPos(AppState.States[ThisState].State, 'LAKE') eq -1) $
  477.     then Begin
  478.         If (AppState.CurrentYearIndex eq $
  479.         N_elements(AppState.States[0].Population) - 1) then Begin
  480. ;
  481. ; If we're in the first year of the census, make the States white.
  482. ;
  483.             Color = [255, 255, 255]
  484.         EndIf Else Begin
  485.             If (AppState.States[ThisState].Population[ $
  486.             AppState.CurrentYearIndex + 1] eq 0) then Begin
  487. ;
  488. ; If the State did not have a census performed in the previous decade,
  489. ; color the State white.
  490. ;
  491.                 Color = [255, 255, 255]
  492.             EndIf Else Begin
  493. ;
  494. ; We had census data from the previous decade, so color the State
  495. ; appropriately.
  496. ;
  497.                 Color = Reform(Colors[*, ThisState])
  498.             EndElse
  499.         EndElse
  500.         AppState.StateSkirts[ThisState]->SetProperty, Color = Color
  501.         AppState.StateFaces[ThisState]->SetProperty, Color = Color
  502.     EndIf
  503. ;
  504. ; If we're on a fast machine, we might want to animate the States
  505. ; individually growing.
  506. ;
  507.     If (AppState.AnimateStates) then Begin
  508.         Dummy = Check_Math()
  509.         AppState.WindowObject->Draw, AppState.ViewObjects[0], $
  510.             Draw_Instance = AppState.Backdrop
  511.     EndIf
  512.     AppState.PreviousScales[OkayPops[I]] = ZScale
  513.  
  514. EndFor
  515. ;
  516. ; If we're not instancing the data, then just draw the view.
  517. ;
  518. Dummy = Check_Math()
  519. If (AppState.AnimateStates eq 0) then Begin
  520.     AppState.WindowObject->Draw, AppState.ViewObjects[0], $
  521.         Draw_Instance = AppState.Backdrop
  522. EndIf
  523. ;
  524. ; Clean up any divide by zero, messages that may have
  525. ; accumulated.
  526. ;
  527. Dummy = Check_Math()
  528. End
  529.  
  530.  
  531. ;Pro USCensus$Animate_Census, AppState
  532. ;
  533. ; Loop over the census years.
  534. ;
  535. ;For J = N_elements(AppState.States[0].Population) - 1, 0, -1 $
  536. ;    Do Begin
  537. ;
  538. ; We rotate the plane on which the States sit at each decade
  539. ; to enhance the relief in the early years of the census and
  540. ; to focus primarily on the east coast.
  541. ;
  542. ;    AppState.ThetaY =  -(J + 4) * 1.25
  543. ;    AppState.CurrentYearIndex = J
  544. ;    Widget_Control, AppState.ThetaYSlider, $
  545. ;        Set_Value = AppState.ThetaY
  546. ;    USCensus$Display_Census_Year, AppState
  547. ;EndFor
  548. ;End
  549.  
  550.  
  551. Pro USCensus$Cleanup, AppState, TLB
  552. ;
  553. ; Handle the widget destruction through a File/Exit or
  554. ; system menu close.
  555. ;
  556. Widget_Control, TLB, Get_UValue = AppState
  557. Obj_Destroy, AppState.ViewObjects[0]
  558. Obj_Destroy, AppState.ViewObjects[1]
  559. Obj_Destroy, AppState.BackdropImage
  560. Obj_Destroy, AppState.WindowObject
  561. Obj_Destroy, AppState.Fonts[0]
  562. Obj_Destroy, AppState.Fonts[1]
  563. Widget_Control, TLB, /Destroy
  564. ;
  565. ; Free the pointers.  Save the whales.
  566. ;
  567. Ptr_Free, AppState.States.pOutline
  568. Ptr_Free, AppState.States.pNormalOutline
  569. Ptr_Free, AppState.States.pHighResOutline
  570. Ptr_Free, AppState.States.pLowIndices
  571. Ptr_Free, AppState.States.pPolygonList
  572. Ptr_Free, AppState.States.pVertexList
  573. End
  574.  
  575.  
  576. Pro D_USCensus_Event, Event
  577. ;
  578. ; This routine is the main event handler for the widget.
  579. ;
  580. Widget_Control, /Hourglass
  581. If (Tag_Names(Event, /Structure_Name) eq 'WIDGET_KILL_REQUEST') $
  582. then Begin
  583.     USCensus$Cleanup, AppState, Event.Top
  584.     !except = AppState.ExceptSave
  585.     Return
  586. EndIf
  587. If (Tag_Names(Event, /Structure_Name) eq 'WIDGET_BASE') then Begin
  588. ;
  589. ; Handle resize events on the top level base.
  590. ;
  591.     Widget_Control, /Hourglass
  592.     Widget_Control, Event.Top, Get_UValue = AppState
  593. ;
  594. ; Size the draw windows appropriately, given the new dimensions
  595. ; of the base.
  596. ;
  597.     ScaleGeom = Widget_Info(AppState.wScale, /Geometry)
  598.     ButtonBaseGeom = Widget_Info(AppState.wControls, /Geometry)
  599.     Widget_Control, AppState.wDraw, XSize = Event.X - $
  600.         ButtonBaseGeom.XSize, $
  601.         YSize = Event.Y - ScaleGeom.YSize
  602.     Widget_Control, AppState.wScale, XSize = Event.X - $
  603.         ButtonBaseGeom.XSize
  604.     Widget_Control, Event.ID, XSize = Event.X, YSize = Event.Y
  605. ;
  606. ; Resize the backdrop, if it's there, and create the
  607. ; new instance.
  608. ;
  609.     If (AppState.Backdrop) then Begin
  610.         AppState.ViewObjects[0]->SetProperty, Transparent = 0
  611.         AppState.StateSurfaceModel->SetProperty, Hide = 1
  612.         AppState.TextObject->SetProperty, Hide = 1
  613.         AppState.BackdropModel->SetProperty, Hide = 0
  614.         AppState.WindowObject->Draw, AppState.ViewObjects[0], $
  615.             /Create_Instance
  616.         AppState.StateSurfaceModel->SetProperty, Hide = 0
  617.         AppState.TextObject->SetProperty, Hide = 0
  618.         AppState.BackdropModel->SetProperty, Hide = 1
  619.         AppState.ViewObjects[0]->SetProperty, Transparent = 1
  620.     EndIf
  621. ;
  622. ; Draw the view.
  623. ;
  624.     AppState.WindowObject->Draw, AppState.ViewObjects[0], $
  625.         Draw_Instance = AppState.Backdrop
  626.     AppState.ScaleObject->Draw, AppState.ViewObjects[1]
  627.     Widget_Control, Event.Top, /Clear_Events
  628.     Return
  629. EndIf
  630. Widget_Control, Event.Top, Get_UValue = AppState
  631. Widget_Control, Event.ID, Get_UValue = UValue
  632. Case UValue of
  633.     'Quit' : Begin
  634.         USCensus$Cleanup, AppState, Event.Top
  635.         Return
  636.         End
  637.     'Draw' : Begin
  638. ;
  639. ; Left mouse button press events cause the selected
  640. ; State's name to be displayed by the text object.
  641. ;
  642.         Case Event.Type of
  643.             0 : Begin
  644.                 If (Event.Press eq 1) then Begin
  645.                     Widget_Control, /Hourglass
  646.                     Picked = AppState.WindowObject->Select( $
  647.                         AppState.ViewObjects[0], [Event.X, Event.Y])
  648.                     If (N_elements(Picked) ne 0) then Begin
  649.                         If (Obj_Valid(Picked[0])) then Begin
  650.                             If (Obj_IsA(Picked[0], 'idlgrmodel')) $
  651.                             then Begin
  652.                                 Picked[0]->IDLGrModel::GetProperty, $
  653.                                     Parent = ParentObject
  654.                             EndIf Else Begin
  655.                                 Picked[0]->GetProperty, Parent = $
  656.                                     ParentObject
  657.                             EndElse
  658.                             ParentObject->GetProperty, UValue = StateName
  659. ;
  660. ; If the object is a State, put the State's name "on the glass".
  661. ; Redrawing the entire scene shouldn't be necessary but I don't
  662. ; know the technique for just getting the text object to change.
  663. ;
  664.                             If (N_elements(StateName) ne 0) then Begin
  665.                                 StateName = StateName[0]
  666.                                 USState = Where(AppState.States.State $
  667.                                     eq StateName, NState)
  668.                                 If (NState ne 0) then Begin
  669.                                     AppState.TextObject->SetProperty, $
  670.                                         String = $
  671.                                         AppState.States[USState[0]].State
  672. ;                                        AppState.ViewObjects[1]->SetProperty, Hide = 1
  673. ;                                        AppState.WindowObject->Draw, AppState.ViewObjects[0], /Draw_Instance
  674. ;                                        AppState.ViewObjects[1]->SetProperty, Hide = 0
  675.                                     Dummy = Check_Math()
  676.                                     AppState.WindowObject->Draw, $
  677.                                         AppState.ViewObjects[0]
  678.                                 EndIf
  679.                             EndIf
  680.                         EndIf
  681.                     EndIf
  682.                 EndIf
  683.                 End
  684.             4 : Begin
  685. ;
  686. ; We got an EXPOSE event on one of the draw windows.
  687. ;
  688.                     AppState.ScaleObject->Draw, AppState.ViewObjects[1]
  689.                     AppState.WindowObject->Draw, AppState.ViewObjects[0]
  690.                     Widget_Control, Widget_Info(Event.ID, /Parent), /Clear_Events
  691.                 End
  692.                 Else:
  693.         EndCase
  694.         End
  695.     'CancelAnimation' : Begin
  696.         Widget_Control, AppState.AnimateButton, Set_Value = 'Animate Census', $
  697.             Set_UValue = 'Animate'
  698.         Widget_Control, Event.Top, /Clear_Events
  699.         End
  700.     'DoingAnimation' : Begin
  701. ;
  702. ; This event is thrown from the controls base.  We use a timer event off
  703. ; this base to indicate "frame advance" in the animation.
  704. ;
  705.         If (AppState.CurrentYearIndex ne 0) then Begin
  706. ;
  707. ; Decrement the year counter (move forward in time), move the slider
  708. ; rotation angle widget, and display the data.
  709. ;
  710.             AppState.CurrentYearIndex = AppState.CurrentYearIndex - 1
  711.             AppState.ThetaY = -(AppState.CurrentYearIndex + 4) * 1.25
  712.             Widget_Control, AppState.ThetaYSlider, $
  713.                 Set_Value = AppState.ThetaY
  714.             USCensus$Display_Census_Year, AppState
  715. ;
  716. ; Throw a timer event from the controls base.  This will put us right
  717. ; back here into this case switch.
  718. ;
  719.             Widget_Control, AppState.wControls, Timer = .001
  720.         EndIf Else Begin
  721. ;
  722. ; We've reached the end of the animation, 1990.  Reset the "Animate Census"
  723. ; button back to its original state, and clear the events.
  724. ;
  725.             Widget_Control, AppState.AnimateButton, Set_Value = 'Animate Census', $
  726.                 Set_UValue = 'Animate'
  727.             Widget_Control, Event.Top, /Clear_Events
  728.         EndElse
  729.         End
  730.     'Animate' : Begin
  731. ;
  732. ; Modify the "Animate Census" Button so it will now throw "CancelAnimation"
  733. ; events.
  734. ;
  735.         AppState.StateSurfaceModel->SetProperty, $
  736.             Transform = AppState.InitialTransform
  737.         Widget_Control, AppState.AnimateButton, $
  738.             Set_Value = 'Cancel Animation', $
  739.             Set_UValue = 'CancelAnimation'
  740. ;
  741. ; Set the year index to point to 1790.
  742. ;
  743.         AppState.CurrentYearIndex = N_elements(AppState.States[0].Population); - 1
  744. ;
  745. ; Toss a timer event from the controls base.  Events from the controls
  746. ; base are interpreted as being "animation frame advance" events.
  747. ;
  748.         Widget_Control, AppState.wControls, Timer = .001
  749.         End
  750.     'Legend' : Begin
  751.         AppState.ScaleObject->Draw, AppState.ViewObjects[1]
  752.         AppState.WindowObject->Draw, AppState.ViewObjects[0]
  753.         End
  754.     'CensusYear' : Begin
  755.         AppState.CurrentYearIndex = $
  756.             N_elements(AppState.States[0].Population) - Event.Value
  757.         USCensus$Display_Census_Year, AppState
  758.         Widget_Control, Event.ID, /Clear_Events
  759.         End
  760.     'YRotation' : Begin
  761.         AppState.ThetaY = Event.Value
  762. ;
  763. ; If individual state animation was in effect, turn it
  764. ; off for the rotation since it serves a purpose only
  765. ; in year changes.
  766. ;
  767.         AnimateStates = AppState.AnimateStates
  768.         AppState.AnimateStates = 0
  769.         USCensus$Display_Census_Year, AppState
  770.         AppState.AnimateStates = AnimateStates
  771.         Widget_Control, Event.ID, /Clear_Events
  772.         End
  773.     'HelpCensusData' : Begin
  774.         If (not XRegistered('About Census Data')) then Begin
  775.             TextTLB = Widget_Base(Group_Leader = Event.Top, /Column)
  776.             Widget_Control, TextTLB, TLB_Set_Title = $
  777.                 'About the Census Data'
  778.             T = Widget_Text(TextTLB, XSize = 60, YSize = 15, $
  779.                 Value = AppState.DataText, /Scroll)
  780.             OkayButton = Widget_Button(TextTLB, Value = 'OK', $
  781.                 UValue = 'KillAboutCensus')
  782.             Widget_Control, TextTLB, /Realize
  783.             XManager, 'About Census Data', TextTLB, Event_Handler = $
  784.                 'D_USCensus_Event'
  785.         EndIf
  786.         End
  787.     'HelpCensusDemo' : Begin
  788.         If (not XRegistered('About Census Demo')) then Begin
  789.             TextTLB = Widget_Base(Group_Leader = Event.Top, /Column)
  790.             Widget_Control, TextTLB, TLB_Set_Title = $
  791.                 'About the Census Demo'
  792.             T = Widget_Text(TextTLB, XSize = 60, YSize = 15, $
  793.                 Value = AppState.DemoText, /Scroll)
  794.             OkayButton = Widget_Button(TextTLB, Value = 'OK', $
  795.                 UValue = 'KillAboutCensus')
  796.             Widget_Control, TextTLB, /Realize
  797.             XManager, 'About Census Demo', TextTLB, Event_Handler = $
  798.                 'D_USCensus_Event'
  799.         EndIf
  800.         End
  801.     'KillAboutCensus' : Begin
  802.         Widget_Control, Event.Top, /Destroy
  803.         Return
  804.         End
  805.     Else :
  806. EndCase
  807. Widget_Control, Event.Top, Set_UValue = AppState
  808. End
  809.  
  810. ;-----------------------------------------------------------------
  811. ;
  812. ;    PURPOSE : cleanup procedure. restore colortable.
  813. ;
  814. pro USCensus_Cleanup, wTopBase
  815.  
  816.     WIDGET_CONTROL, wTopBase, GET_UVALUE=sState, /NO_COPY
  817.  
  818.     ;  Restore the color table.
  819.     ;
  820.     TVLCT, sState.colorTable
  821.  
  822.     if widget_info(sState.groupBase, /valid) then $
  823.         widget_control, sState.groupBase, /map
  824.  
  825. end   ;  of USCensus_Cleanup
  826.  
  827.  
  828. Pro D_Uscensus, XSize = XSize, YSize = YSize, Axes = Axes, $
  829.     Animate_States = Animate_States, Backdrop = Backdrop, $
  830.     New_England = New_England, Depth = Depth, $
  831.     Group_Leader = Group_Leader, AppTLB = AppTLB
  832. ;+
  833. ;  FILE:
  834. ;       D_Uscensus.pro
  835. ;
  836. ;  CALLING SEQUENCE: D_Uscensus [, GROUP_LEADER = GROUP_LEADER $]
  837. ;                             [, XSIZE = XSIZE $]
  838. ;                             [, YSIZE = YSIZE $]
  839. ;                             [, /AXES $]
  840. ;                             [, /ANIMATE_STATES $]
  841. ;                             [, /NEW_ENGLAND $]
  842. ;                             [, /BACKDROP $]
  843. ;                             [, /DEPTH]
  844. ;
  845. ;  PURPOSE:
  846. ;       This application also illustrates handling draw widget base
  847. ;       resizing and exposure events in the context of Object
  848. ;       Graphics, pointer and object heap variable management and
  849. ;       cleanup, and, when /BACKDROP is enabled, instancing of IDLgrView
  850. ;       objects and image texture mapping to an IDLgrSurface object.
  851. ;
  852. ;       The RGB Object Graphics color model is used exclusively in this
  853. ;       demo; None of the code uses Color Index (CI) model.
  854. ;
  855. ;       The procedure was authored by the Professional Services Group
  856. ;       of Research Systems.  For those desiring a larger
  857. ;       implementation, we can be contacted (psg@rsinc.com) for
  858. ;       consulting and custom coding.
  859. ;
  860. ;  KEYWORD PARAMETERS:
  861. ;       GROUP_LEADER can be set to the ID of a parent widget when
  862. ;       this routine is called as a compound widget.
  863. ;
  864. ;       APPTLB returns the application top level base, mainly for
  865. ;       use in the IDL Demo (i.e., don't worry about this if you
  866. ;       aren't RSI.)
  867. ;
  868. ;       XSIZE, YSIZE can be used to define the size of the main
  869. ;       draw window.  By default, the values are 467 and 376 pixels,
  870. ;       respectively.
  871. ;
  872. ;       /AXES specifies that lines showing the X, Y, and Z
  873. ;       axes should be rendered.  By default these are not shown.
  874. ;
  875. ;       /ANIMATE_STATES when set allows States to be individually
  876. ;       rendered when a new year of data is displayed.  By default
  877. ;       all States are scaled before the view is rendered.  This
  878. ;       option is recommended only on machines with good rendering
  879. ;       speed, such as a Pentium Pro 200 or Sun Ultra.
  880. ;
  881. ;       /BACKDROP when set causes a backdrop image to be drawn behind
  882. ;       the USA map.  It's a good example of view object instancing.
  883. ;       This is recommended only for machines with TrueColor displays
  884. ;       and good rendering speed.  By default, the backdrop image is
  885. ;       not displayed.
  886. ;
  887. ;       /DEPTH turns on depth cueing in the view.  By default, depth
  888. ;       cueing is not performed.
  889. ;
  890. ;  RETURN VALUE:
  891. ;  MAJOR TOPICS: Visualization, Analysis, Demo, Language
  892. ;
  893. ;  CATEGORY:
  894. ;       IDL 5.0
  895. ;
  896. ;  INTERNAL FUNCTIONS and PROCEDURES:
  897. ;       fun USCensus$ZCOLORS       - Determine color to shade State
  898. ;                                    objects based on population
  899. ;                                    gain or loss.
  900. ;       pro USCensus$NEW_COORDINATES
  901. ;                                  - Turn latitutde/longitudes for
  902. ;                                    State outlines into device
  903. ;                                    coordinates, and build the
  904. ;                                    "skirts".
  905. ;       pro USCensus$BUILD_BACKDROP
  906. ;                                  - Build the backdrop "drapery"
  907. ;                                    objects
  908. ;       pro USCensus$BUILD_SCALE_LEGEND
  909. ;                                  - Build the legend for the display
  910. ;       pro USCensus$BUILD_STATE_OBJECTS
  911. ;                                  - Build the individual State
  912. ;                                    objects
  913. ;       pro USCensus$DISPLAY_CENSUS_YEAR
  914. ;                                  - Draw the scene for the currently
  915. ;                                    selected year
  916. ;       pro USCensus$ANIMATE_CENSUS
  917. ;                                  - Animate the census data from 1790
  918. ;                                    to 1990
  919. ;       pro USCensus$CLEANUP       - Clean up objects and heap
  920. ;                                    variables when the application
  921. ;                                    is completed.
  922. ;       pro USCensus_EVENT         - The main event handler
  923. ;
  924. ;  EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
  925. ;       states.sav                 - IDL SAVE file containing State
  926. ;                                    outlines and Census data.
  927. ;
  928. ;  REFERENCE: IDL Reference Guide, IDL User's Guide
  929. ;
  930. ;  NAMED STRUCTURES:
  931. ;       none.
  932. ;
  933. ;  COMMON BLOCKS:
  934. ;       none.
  935. ;
  936. ;  SYSTEM VARIABLES:
  937. ;       none.
  938. ;
  939. ;  MODIFICATION HISTORY:
  940. ;       3/97,       JLP   - Completed version for IDL 5.0.
  941. ;       4/11/97,    JLP   - Restricted rotation angle selection
  942. ;                           Added ability to stop animation
  943. ;                           Modified viewport size
  944. ;                           Added check_math() traps for text objects
  945. ;-
  946. ;--------------------------------------------------------------------
  947. If (XRegistered('D_Uscensus', /NoShow)) then Begin
  948.     v = Dialog_Message('An instance of D_Uscensus is already running.')
  949.     Return
  950. EndIf
  951. If (N_elements(Group_Leader) ne 0) then Begin
  952.     If (N_elements(Group_Leader) eq 1) then Begin
  953.         OkayGL = Widget_Info(Group_Leader, /Valid_ID)
  954.     EndIf Else Begin
  955.         OkayGL = 0
  956.     EndElse
  957.     If (not OkayGL) then Begin
  958.         v = Dialog_Message('The GROUP_LEADER parameter is invalid.')
  959.         Return
  960.     EndIf
  961.         groupBase = Group_Leader
  962. EndIf else groupBase = 0L
  963.  
  964. ngroup = N_elements(Group_Leader)
  965.  
  966. ;    ;  Create the starting up message.
  967. ;    ;
  968. ;    if (ngroup EQ 0) then begin
  969. ;        drawbase = startmes()
  970. ;    endif else begin
  971. ;        drawbase = startmes(GROUP=group)
  972. ;    endelse
  973.  
  974.     ;  Get the current color vectors to restore
  975.     ;  when this application is exited.
  976.     ;
  977.     TVLCT, savedR, savedG, savedB, /GET
  978.  
  979.     ;  Build color table from color vectors
  980.     ;
  981.     colorTable = [[savedR],[savedG],[savedB]]
  982.  
  983.     ;  Get the tips.
  984.     ;
  985. ;    sText = getTips('uscensus.tip')
  986.     sText = getTips(filepath('uscensus.tip', $
  987.         SUBDIR=['examples','demo', 'demotext']) )
  988.  
  989.  
  990. ;
  991. ; On slow platforms, we only use New England.
  992. ;
  993. NewEnglandStates = ['MAINE', 'NEW HAMPSHIRE', 'VERMONT', $
  994.     'MASSACHUSETTS', 'CONNECTICUT', 'RHODE ISLAND']
  995. NewEngland = Keyword_Set(New_England)
  996. If (Keyword_Set(Depth)) then Begin
  997.     Depth_Cue = [-1.5, 1.]
  998. EndIf Else Begin
  999.     Depth_Cue = [0., 0.]
  1000. EndElse
  1001. ;
  1002. ; We show relative population changes from decade to decade
  1003. ; via color indices.
  1004. ;
  1005. RangeMax = [1., 1.01, 1.1, 1.2, 1.5, 2., 3.]
  1006. Colors = [ $
  1007.     [255, 0, 0], $
  1008.     [115, 40, 100], $
  1009.     [105, 95, 105], $
  1010.     [15, 150, 0], $
  1011.     [0, 255, 0], $
  1012.     [105, 105, 200], $
  1013.     [145, 195, 125], $
  1014.     [195, 215, 255]]
  1015. PopulationScale = {RangeMax : RangeMax, Colors : Colors}
  1016. ;
  1017. ; Set the draw window size.
  1018. ;
  1019. DEVICE, GET_SCREEN_SIZE = screenSize
  1020. XDim= 0.55 * screenSize(0)
  1021. YDim= 0.8 * XDim
  1022.  
  1023. ;XDim = 467
  1024. ;YDim = 376
  1025.  
  1026. If (N_elements(XSize) eq 1) then Begin
  1027.     XDim = XSize[0] > 0
  1028. EndIf
  1029. If (N_elements(YSize) eq 1) then Begin
  1030.     YDim = YSize[0] > 0
  1031. EndIf
  1032. ;
  1033. ; Restore the States database.  This contains
  1034. ; the State outlines and census data.
  1035. ;
  1036. F = FindFile('states.sav', Count = Count)
  1037. If (Count eq 0) then Begin
  1038.     Restore, FilePath('states.sav', SubDir = $
  1039.         ['examples', 'demo', 'demodata'])
  1040. EndIf Else Begin
  1041.     Restore, 'states.sav'
  1042. EndElse
  1043. NStates = N_elements(States)
  1044. NYears = N_elements(States[0].Population)
  1045. For I = 0, NStates - 1 Do Begin
  1046.     If (Ptr_Valid(States[I].pLowIndices)) then Begin
  1047.         States[I].pOutline = Ptr_New((*States[I].pHighResOutline) $
  1048.             [*, *States[I].pLowIndices])
  1049.     EndIf Else Begin
  1050.         States[I].pOutline = States[I].pHighResOutline
  1051.     EndElse
  1052. EndFor
  1053. ;
  1054. ; Calculate State outlines and extruded skirts in normalized
  1055. ; coordinates based on the current window size.
  1056. ;
  1057. USCensus$New_Coordinates, States, XDim, YDim
  1058. ;
  1059. ; Create widgets.
  1060. ;
  1061. If (Keyword_Set(Group_Leader)) then Begin
  1062.     wBase = Widget_Base(/COLUMN, Group=Group_Leader, MBar=MenuBar, $
  1063.         XPad = 0, YPad = 0, Title = 'US Census Data', $
  1064.         /TLB_Kill_Request_Events, /TLB_Size_Events, Space = 0)
  1065. EndIf Else Begin
  1066.     wBase = Widget_Base(/COLUMN, MBar = MenuBar, $
  1067.         XPad = 0, YPad = 0, Title = 'US Census Data', $
  1068.         /TLB_Kill_Request_Events, /TLB_Size_Events, Space = 0)
  1069. EndElse
  1070.  
  1071. wBase1 = WIDGET_BASE(wBase,/Row)
  1072.  
  1073. AppTLB = wBase
  1074. FileMenu = Widget_Button(MenuBar, Value = 'File', /Menu)
  1075. QuitButton = Widget_Button(FileMenu, Value = 'Quit', /Separator, $
  1076.     UValue = 'Quit')
  1077.  
  1078. HelpMenu = Widget_Button(MenuBar, Value = 'About', /Help,  /Menu)
  1079. HelpButton = Widget_Button(HelpMenu, Value = 'About the data...', $
  1080.     UValue = 'HelpCensusData')
  1081. HelpButton = Widget_Button(HelpMenu, Value = 'About the demo...', $
  1082.     UValue = 'HelpCensusDemo')
  1083. DataText = [ $
  1084.     '', $
  1085.     '  This demonstration illustrates United States Census Bureau  ', $
  1086.     '  data collected in the decades 1790-1990.', $
  1087.     '',  $
  1088.     '  State heights represent total population, while colors', $
  1089.     '  indicate relative population change from the preceding', $
  1090.     "  decade's census.", $
  1091.     '', $
  1092.     '  States for which no data were collected in the previous', $
  1093.     '  decade are displayed in white.']
  1094. DemoText = [ $
  1095.     '', $
  1096.     '  The "Animate Census" button will cycle through the U.S.', $
  1097.     '  Census data from 1790 to 1990.  At each decade, the field', $
  1098.     '  of view is rotated slightly about the Y-axis, roughly', $
  1099.     '  bisecting the map, in order to provide a changing perspective.', $
  1100.     ' ', $
  1101.     '  The "Rotation Angle" slider widget can be used to explicitly', $
  1102.     '  define an angle about the Y-axis at which to view the data.', $
  1103.     '', $
  1104.     "  Clicking on a State will cause the State's name to be", $
  1105.     "  displayed, illustrating Object Graphics' capabilites for", $
  1106.     '  interactively selecting 3D objects.', $
  1107.     '', $
  1108.     '  The "Select Census Year" pull-down menu lets you select', $
  1109.     '  a specific year of data to be shown.', $
  1110.     '', $
  1111.     "  The individual State outlines were derived from IDL's map", $
  1112.     '  database.', $
  1113.     '', $
  1114.     '  This procedure was authored by the Professional Services', $
  1115.     '  Group of Research Systems.  For those desiring a larger', $
  1116.     '  implementation, the Professional Services Group can be', $
  1117.     '  contacted (psg@rsinc.com) for consulting and custom coding.']
  1118. wControls = Widget_Base(wBase1, XPad = 1, YPad = 1, Space = 1, $
  1119.     /Column, Frame = 1, UValue = 'DoingAnimation')
  1120. AnimateButton = Widget_Button(wControls, Value = 'Animate Census', $
  1121.     UValue = 'Animate')
  1122. MenuItem = {CW_PDMENU_S, Flags : 0, Name : ''}
  1123. CensusMenuItems = Replicate(MenuItem, NYears + 1)
  1124. CensusMenuItems.Flags = [1, IntArr(NYears - 1), 2]
  1125. CensusMenuItems.Name = ['Select Census Year', $
  1126.     StrTrim(1790 + Indgen(NYears)*10, 2)]
  1127. CensusMenu = CW_PDMenu(wControls, CensusMenuItems, $
  1128.     UValue = 'CensusYear', /Return_Index)
  1129. ThetaYSlider = Widget_Slider(wControls, Maximum = 40, Minimum = -40, $
  1130.     Value =0, UValue = 'YRotation', Title = 'Rotation Angle')
  1131. Drawbase = Widget_Base(wBase1, /Column, XPad = 0, YPad = 0, Space = 0, Frame = 0)
  1132. wDraw = Widget_Draw(DrawBase, XSize = XDim, YSize = YDim, $
  1133.     /Button_Events, UValue = 'Draw', Retain = 0, /Expose_Events, $
  1134.     Graphics_Level = 2)
  1135. wScale = Widget_Draw(DrawBase, XSize = XDim, YSize = 60, $
  1136.     UValue = 'Legend', Retain = 0, /Expose_Events, $
  1137.     Graphics_Level = 2)
  1138.  
  1139.         ;  Create the status line label.
  1140.         ;
  1141.         wStatusBase = WIDGET_BASE(wBase, MAP=0, /ROW)
  1142.  
  1143.             nWidgets = 2
  1144.             wText = LONARR(nWidgets)
  1145.             widTips, wStatusBase, sText.text, XSIZE=36, $
  1146.                 YSIZE=3, NWIDGETS=nWidgets, wText
  1147.  
  1148. ;
  1149. ; Realize the base widget.
  1150. ;
  1151. Widget_Control, wBase, /Realize
  1152.  
  1153.     ;  Size the tips widgets.
  1154.     ;
  1155.     sizeTips, wBase, wText, wStatusBase
  1156.  
  1157. Widget_Control, /Hourglass
  1158. ;
  1159. ; Get the window objects associated with the two
  1160. ; draw widgets we've created.
  1161. ;
  1162. Widget_Control, wDraw, Get_Value = WindowObject
  1163. Widget_Control, wScale, Get_Value = ScaleObject
  1164. ;
  1165. ; Create the views.  One will contain the USA and backdrop and
  1166. ; the other will contain the scale legend.
  1167. ;
  1168. ViewObject1 = Obj_New('IDLgrView', Projection = 1, $
  1169.     Viewplane_Rect=[-.2, -.11, .4, .22], Color = [255, 255, 255], $
  1170.     ZClip = [2., -1.], Depth_Cue = Depth_Cue)
  1171. ViewObject2 = Obj_New('IDLgrView', Projection = 1, $
  1172.     Viewplane_Rect=[-1, -1, 2, 2], Color = [0, 0, 0])
  1173. ;
  1174. ; Build the backdrop
  1175. ;
  1176. BackdropModel = Obj_New('IDLgrModel')
  1177. USCensus$Build_Backdrop, BackdropImage, BackdropObject
  1178. BackdropModel->Add, BackdropObject
  1179. If (not Keyword_Set(Backdrop)) then Begin
  1180.     BackdropObject->SetProperty, Hide = 1
  1181. EndIf
  1182. ;
  1183. ; Create fonts for labels.
  1184. ;
  1185. Fonts = ObjArr(2)
  1186. Fonts[0] = Obj_New('IDLgrFont', 'Times*Bold', Size = 14 - $
  1187.     2*(!d.y_ch_size gt 12))
  1188. Fonts[1] = Obj_New('IDLgrFont', 'Times', Size = 12 - $
  1189.     2*(!d.y_ch_size gt 12))
  1190. ;
  1191. ; Create the population scale legend, add it to the
  1192. ; appropriate view, and draw it.
  1193. ;
  1194. USCensus$Build_Scale_Legend, PopulationScale, Fonts[1], ScaleModel
  1195. ViewObject2->Add, ScaleModel
  1196. ScaleObject->Draw, ViewObject2
  1197. ;
  1198. ; Create a model for lights and place an ambient and
  1199. ; directional light into the appropriate view.
  1200. ;
  1201. LightFrame = Obj_New('IDLgrModel')
  1202. Light1 = Obj_New('IDLgrLight', Type = 0, Intensity = 0.85, $
  1203.     Color = [255, 255, 255])
  1204. Light2 = Obj_New('IDLgrLight', Location = [0, 2, 2], Type = 1, $
  1205.     Color = [255, 255, 255], Intensity = .5)
  1206. LightFrame->Add, Light1
  1207. LightFrame->Add, Light2
  1208. ViewObject1->Add, LightFrame
  1209.  
  1210. USCensus$Build_State_Objects, States, StateSurfaceModel, $
  1211.     StateObjects, StateSkirts, StateFaces, StateOutlines
  1212. ;
  1213. ; If we're only looking at New England, hide the other States.
  1214. ;
  1215. If (NewEngland) then Begin
  1216.     For I = 0, NStates - 1 Do Begin
  1217.         IsNewEngland = Where(NewEnglandStates eq States[I].State, $
  1218.             NIsNewEngland)
  1219.         If (NIsNewEngland eq 0) then Begin
  1220.             StateObjects[I]->SetProperty, Hide = 1
  1221.         EndIf
  1222.     EndFor
  1223. EndIf
  1224. ;
  1225. ; Sort of center the USA (or New England) on the origin in the
  1226. ; X-Y plane.
  1227. ;
  1228. ;StateSurfaceModel->Translate, -.46 - NewEngland*.13, $
  1229. ;    -.24 - NewEngland*.041, 0.
  1230. StateSurfaceModel->Translate, -.44 - NewEngland*.13, $
  1231.     -.24 - NewEngland*.041, 0.
  1232. ;
  1233. ; Scale up New England if we're not looking at the entire USA.
  1234. ;
  1235. If (NewEngland) then Begin
  1236.     StateSurfaceModel->Scale, 4., 4., 1.
  1237. EndIf
  1238. ;
  1239. ; Rotate the States 30 degrees about the Y axis.  This lets us
  1240. ; look at the Z values from an oblique angle.
  1241. ;
  1242. ThetaY = -30 ;*(1. - (Keyword_Set(Depth)*.75))
  1243. StateSurfaceModel->Rotate, [0., 1., 0.], ThetaY
  1244. ;
  1245. ; Translate the model up Z toward the viewer so we can
  1246. ; make room for the backdrop.
  1247. ;
  1248. StateSurfaceModel->Translate, 0., 0., .5
  1249. ;
  1250. ; Create crosshairs at the origin, if requested.
  1251. ;
  1252. If (Keyword_Set(Axes)) then Begin
  1253.     AxisObject = Obj_New('IDLgrModel')
  1254.     Xaxis = Obj_New('IDLgrPolyline', [[-.2, 0., 0.], [.2, 0., 0.]], $
  1255.         Color=[0, 0, 0], Thick=1.2)
  1256.     Yaxis = Obj_New('IDLgrPolyline', [[0., -.2, 0.], [0., .2, 0.]], $
  1257.         Color=[0, 0, 0], Thick=1.2)
  1258.     Zaxis = Obj_New('IDLgrPolyline', [[0., 0., -.2], [0., 0., .2]], $
  1259.         Color=[0, 0, 0], Thick=1.2)
  1260.     AxisObject->Add, XAxis
  1261.     AxisObject->Add, YAxis
  1262.     AxisObject->Add, ZAxis
  1263.     ViewObject1->Add, AxisObject
  1264. EndIf
  1265. ;
  1266. ; Add the State surface to the appropriate view.
  1267. ;
  1268. ViewObject1->Add, StateSurfaceModel
  1269. ;
  1270. ; Save the initial transformation matrix.  This allows
  1271. ; us to return to this initial position if we want
  1272. ; to re-animate the data.
  1273. ;
  1274. StateSurfaceModel->GetProperty, Transform = InitialTransform
  1275. ;
  1276. ; If we're employing a backdrop image, we only need to draw it
  1277. ; once as an instance and use that in subsequent draws of the USA.
  1278. ;
  1279. If (Keyword_Set(Backdrop)) then Begin
  1280.     ViewObject1->Add, BackdropModel
  1281.     StateSurfaceModel->SetProperty, Hide = 1
  1282.     BackdropModel->SetProperty, Hide = 0
  1283.     WindowObject->Draw, ViewObject1, /Create_Instance
  1284.     StateSurfaceModel->SetProperty, Hide = 0
  1285.     BackdropModel->SetProperty, Hide = 1
  1286.     ViewObject1->SetProperty, Transparent = 1
  1287. EndIf
  1288. ;
  1289. ; Add a text object which will hold the census year.  It
  1290. ; also holds the name of the State when the user clicks.
  1291. ;
  1292. TextModel = Obj_New('IDLgrModel')
  1293. If (Keyword_Set(Backdrop)) then Begin
  1294.     TextColor = [255, 255, 155]
  1295. Endif Else Begin
  1296.     TextColor = [0, 0, 0]
  1297. EndElse
  1298. TextObject = Obj_New('IDLgrText',  '', Location = [.13, -.08], $
  1299.     Color = TextColor, /OnGlass, Font = Fonts[0], Alignment = .5)
  1300. TextModel->Add, TextObject
  1301. ViewObject1->Add, TextModel
  1302. ;
  1303. ; Save the application state.
  1304. ;
  1305. ExceptSave = !except
  1306. !except = 0
  1307. AppState = { $
  1308.     ViewObjects        : [ViewObject1, ViewObject2], $
  1309.     WindowObject    : WindowObject, $
  1310.     ScaleObject        : ScaleObject, $
  1311.     wDraw            : wDraw, $
  1312.     wScale            : wScale, $
  1313.     wControls        : wControls, $
  1314.     TextObject        : TextObject, $
  1315.     States            : States, $
  1316.     StateObjects    : StateObjects, $
  1317.     StateOutlines    : StateOutlines, $
  1318.     StateSkirts        : StateSkirts, $
  1319.     StateFaces        : StateFaces, $
  1320.     StateSurfaceModel    : StateSurfaceModel, $
  1321.     ThetaY            : ThetaY, $
  1322.     ThetaYSlider    : ThetaYSlider, $
  1323.     CurrentYearIndex: NYears - 1, $
  1324.     Fonts            : Fonts, $
  1325.     BackdropModel    : BackdropModel, $
  1326.     BackdropImage    : BackdropImage, $
  1327.     DepthCue        : Depth_Cue, $
  1328.     AnimateStates    : Keyword_Set(Animate_States), $
  1329.     Backdrop        : Keyword_Set(Backdrop), $
  1330.     PreviousScales    : FltArr(N_elements(States)) + 1., $
  1331.     MaxZValue        : Max(States.Population) * 1.2, $
  1332.     PopulationScale    : PopulationScale, $
  1333.     InitialTransform: InitialTransform, $
  1334.     DemoText        : DemoText, $
  1335.     DataText        : DataText, $
  1336.     AnimateButton    : AnimateButton, $
  1337.     ExceptSave        : ExceptSave, $
  1338.         ColorTable: colorTable, $              ; Color table to restore at exit
  1339.         groupBase: groupBase $                 ; Base of Group Leader
  1340.     }
  1341. Widget_Control, ThetaYSlider, Set_Value = ThetaY
  1342.  
  1343. Widget_Control, wBase, Set_UValue = AppState
  1344.  
  1345. ;Widget_Control, wBase, /Clear_Events
  1346.  
  1347. ;    ;  Destroy the starting up window.
  1348. ;;    ;
  1349. ;    WIDGET_CONTROL, drawbase, /DESTROY
  1350. ;
  1351. ;    ;  Map the top level base.
  1352. ;    ;
  1353. ;    WIDGET_CONTROL, wBase, MAP=1
  1354. ;
  1355. ;Widget_Control, wBase, /HOURGLASS
  1356.  
  1357. USCensus$Display_Census_Year, AppState
  1358. ;
  1359. ; If we're only showing New England, we want to be a little more
  1360. ; fancy; make New England act like a pendulum.
  1361. ;
  1362. ;If (NewEngland and not (Keyword_set(Depth))) then Begin
  1363. ;    AppState.WindowObject->SetProperty, QUALITY = (NewEngland eq 1)
  1364. ;    For I = 30, 394, 4 Do Begin
  1365. ;        Direction = (I mod 180 lt 90) - Long((I mod 180 ge 90))
  1366. ;
  1367. ; Translate the State back to the XY plane, rotate it about Y and Z
  1368. ; then translate it back above the XY plane.
  1369. ;
  1370. ;        StateSurfaceModel->Translate, 0., 0., -.5
  1371. ;        StateSurfaceModel->Rotate, [0., 1., 0.], 4.*Direction
  1372. ;        StateSurfaceModel->Rotate, [0., 0., 1.], 4.*Direction
  1373. ;        StateSurfaceModel->Translate, 0., 0., .5
  1374. ;        AppState.WindowObject->Draw, AppState.ViewObjects[0], $
  1375. ;            Draw_Instance = Keyword_Set(Backdrop)
  1376. ;    EndFor
  1377. ;EndIf
  1378. ;Widget_Control, wBase, /Clear_Events
  1379.  
  1380.  
  1381. XManager, 'D_Uscensus', wBase, $
  1382.     /No_Block, $
  1383.     CLEANUP='USCensus_Cleanup'
  1384.  
  1385. Return
  1386. End
  1387.